/*
 * Area.java - Created on June 7, 2007
 *
 * Copyright 2006,2007,2009 Matthieu Chase Heimer
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package com.macro10.xroads.entity;

import com.macro10.switchboard.entity.SettingStore;
import com.macro10.switchboard.xml.generated.XMLExit;
import com.macro10.xml.SwitchboardParser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;

@NamedQueries({
    @NamedQuery(name = "findAreaByName", query = "SELECT a FROM Area a WHERE a.areaName = :areaName")
})
@Entity
public class Area extends SettingStore {

    @Column(unique = true, nullable = false)
    private String areaName;
    @OneToMany(mappedBy = "area", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
    private List<Avatar> avatars;
//    @OneToMany(mappedBy = "area", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REMOVE})
//    @OrderBy("creationTime")
//    private List<Monster> monsters = new ArrayList();
//    @Lob
//    private String items;

    public Area() {
    }

    public Area(String areaName) {
        this.areaName = areaName;
    }

    public String getAreaName() {
        return areaName;
    }

    public long getType() {
        return SwitchboardParser.getInstance().getXMLArea(areaName).getType();
    }

    public long getFlags() {
        Long flags = SwitchboardParser.getInstance().getXMLArea(areaName).getFlags();
        if (flags == null) {
            return 0;
        } else {
            return flags;
        }
    }

    public List<Exit> getExits() {
        List<XMLExit> xmlExits = SwitchboardParser.getInstance().getXMLArea(areaName).getExits();
        List<Exit> exits = new ArrayList<Exit>();
        for (XMLExit xmlExit : xmlExits) {
            exits.add(new Exit(xmlExit.getPosition(), xmlExit.getTargetArea()));
        }
        Collections.sort(exits);
        return exits;
    }

    /**
     * Makes a database query to get all online avatars in the area represented 
     * by this object.
     * @return A list of avatars in an area.
     */
    public List<Avatar> getOnlineAvatars() {
        List<Avatar> onlineAvatars = new ArrayList<Avatar>();
        for (Avatar avatar : avatars) {
            if (avatar.isOnline()) {
                onlineAvatars.add(avatar);
            }
        }
        Collections.sort(onlineAvatars);
        return onlineAvatars;
    }

    public List<Avatar> getAvatars() {
        return avatars;
    }

    /** Calls getOnlineAvatars() to get a list of online avatars in this area 
     * and then removes the avatars in avatarIds from that list.
     * @param avatarIds The avatars not to include
     * @return A subset of the avatars in an area.
     */
    public List<Avatar> getAvatarsExcept(String... avatarIds) {
        List<Avatar> onlineAvatars = getOnlineAvatars();
        Avatar avatarToRemove = new Avatar();
        for (String avatarId : avatarIds) {
            avatarToRemove.setAvatarId(avatarId);
            onlineAvatars.remove(avatarToRemove);
        }
        Collections.sort(onlineAvatars);
        return onlineAvatars;
    }

//    //TODO figure out the order by (@OrderBy) issue;
//    public List<Monster> getMonsters() {
//        return monsters;
//    }
//
//    public List<Item> getItems() {
//        return Item.getItems(items.split(","));
//    }
//
//    public boolean removeItem(Item item) {
//        if (item == null || items == null || items.trim().length() == 0) {
//            return false;
//        } else {
//            String[] ia = items.split(",");
//            int match = -1;
//            for (int i = 0; i < ia.length; i++) {
//                if (ia[i].equals(item.getId())) {
//                    match = i;
//                    break;
//                }
//            }
//            if (match != -1) {
//                if (ia.length == 1) {
//                    items = "";
//                } else {
//                    items = "";
//                    for (int i = 0; i < ia.length; i++) {
//                        if (i != match) {
//                            if (items.length() > 0) {
//                                items += ",";
//                            }
//                            items += ia[i];
//                        }
//                    }
//                }
//                return true;
//            } else {
//                return false;
//            }
//        }
//    }
//
//    public void addItem(Item item) {
//        if (item != null) {
//            if (items == null || items.trim().length() == 0) {
//                items = item.getId();
//            } else {
//                items += "," + item.getId();
//            }
//        }
//    }
//
//    /**
//     * Find a monster in the area.
//     * @param name The name or partial name of the monster.
//     * @return
//     */
//    public SearchResult findMonster(String name, Locale locale) {
//        SearchResult result = new SearchResult();
//
//        //TODO fix orderby here with a SortedSet?
//        //TODO fix localization like with items
//        for (Monster monster : monsters) {
//            String monsterName = monster.getName();
//            if (monsterName.equalsIgnoreCase(name)) {
//                result.exactMatch = true;
//                result.object = monster;
//                result.objectsMatched++;
//                result.uniqueMatches = 1;
//            } else if (name.length() > monsterName.length()) {
//                continue;
//            } else if (name.equalsIgnoreCase(monsterName.substring(0, name.length()))) {
//                if (!result.exactMatch) {
//                    result.objectsMatched++;
//                    if (result.object == null) {
//                        result.object = monster;
//                    }
//                    if (!result.names.contains(monsterName)) {
//                        result.uniqueMatches++;
//                        result.names.add(monsterName);
//                    }
//                }
//            }
//        }
//        return result;
//    }
//
//    /**
//     * Find an avatar in the area.
//     * @param name The name or partial name of the avatar.
//     * @return
//     */
//    public SearchResult findAvatar(String name) throws Exception {
//        SearchResult result = new SearchResult();
//
//        List<Avatar> onlineAvatars = getOnlineAvatars();
//        for (Avatar avatar : onlineAvatars) {
//            String avatarName = avatar.getAvatarId();
//            if (avatarName.equalsIgnoreCase(name)) {
//                if (!result.exactMatch) {
//                    result.objectsMatched = 0;
//                }
//                result.exactMatch = true;
//                result.object = avatar;
//                result.objectsMatched++;
//                result.uniqueMatches = 1;
//            } else if (name.length() > avatarName.length()) {
//                continue;
//            } else if (!result.exactMatch && name.equalsIgnoreCase(avatarName.substring(0, name.length()))) {
//                result.objectsMatched++;
//                if (result.object == null) {
//                    result.object = avatar;
//                }
//                if (!result.names.contains(avatarName)) {
//                    result.uniqueMatches++;
//                    result.names.add(avatarName);
//                }
//            }
//        }
//        return result;
//    }
//
//    /**
//     * Find an item in the area.
//     * Multiple partial matches are ok if the item is the same type.
//     * @param name The name or partial name of the item.
//     * @param locale The locale that the name param is in.
//     * @return
//     */
//    public SearchResult findItem(String name, Locale locale) {
//        SearchResult result = new SearchResult();
//
//        if (items != null || items.trim().length() > 0) {
//            String[] ia = items.split(",");
//
//            for (String itemId : ia) {
//                Item item = Item.getItem(itemId);
//                String itemName = Output.getmsg(item.getShortMessageKey(), locale);
//                if (itemName.equalsIgnoreCase(name)) {
//                    if (!result.exactMatch) {
//                        result.objectsMatched = 0;
//                    }
//                    result.exactMatch = true;
//                    result.object = item;
//                    result.objectsMatched++;
//                    result.uniqueMatches = 1;
//                } else if (name.length() > itemName.length()) {
//                    continue;
//                } else if (!result.exactMatch && name.equalsIgnoreCase(itemName.substring(0, name.length()))) {
//                    result.objectsMatched++;
//                    if (result.object == null) {
//                        result.object = item;
//                    }
//                    if (!result.names.contains(itemName)) {
//                        result.uniqueMatches++;
//                        result.names.add(itemName);
//                    }
//                }
//            }
//        }
//        return result;
//    }
//
//    /**
//     * Find something with some hit points, typically to attack or heal.
//     * @param name The name or partial name of the target.
//     * @return
//     * @throws java.lang.Exception
//     */
//    public SearchResult findTarget(String name, Locale locale) throws Exception {
//        SearchResult result = new SearchResult();
//
//        SearchResult monsterResult = findMonster(name, locale);
//
//        if (monsterResult.exactMatch) {
//            return monsterResult;
//        }
//
//        SearchResult avatarResult = findAvatar(name);
//
//        if (avatarResult.exactMatch) {
//            return avatarResult;
//        }
//
//        result.objectsMatched = monsterResult.objectsMatched + avatarResult.objectsMatched;
//        result.uniqueMatches = monsterResult.uniqueMatches + avatarResult.uniqueMatches;
//        result.names.addAll(monsterResult.names);
//        result.names.addAll(avatarResult.names);
//        //result.names.addAll(itemResult.names);
//        if(monsterResult.object != null) {
//            result.object = monsterResult.object;
//        } else if(avatarResult.object != null) {
//            result.object = avatarResult.object;
//        }
//
//        return result;
//    }
//
//    /**
//     * Find an object in the area, typically for a look action or a spell.
//     * Prefer and exact match over anything else.
//     * @param name The name or partial name of the target.
//     * @return
//     * @throws java.lang.Exception
//     */
//    public SearchResult findObject(String name, Locale locale) throws Exception {
//        SearchResult result = new SearchResult();
//
//        SearchResult monsterResult = findMonster(name, locale);
//
//        if (monsterResult.exactMatch) {
//            return monsterResult;
//        }
//
//        SearchResult avatarResult = findAvatar(name);
//
//        if (avatarResult.exactMatch) {
//            return avatarResult;
//        }
//
//        SearchResult itemResult = findItem(name, locale);
//
//        if(itemResult.exactMatch) {
//            return itemResult;
//        }
//
//        result.objectsMatched = monsterResult.objectsMatched + avatarResult.objectsMatched + itemResult.objectsMatched;
//        result.uniqueMatches = monsterResult.uniqueMatches + avatarResult.uniqueMatches + itemResult.uniqueMatches;
//        result.names.addAll(monsterResult.names);
//        result.names.addAll(avatarResult.names);
//        result.names.addAll(itemResult.names);
//        if(monsterResult.object != null) {
//            result.object = monsterResult.object;
//        } else if(avatarResult.object != null) {
//            result.object = avatarResult.object;
//        } else if(itemResult.object != null) {
//            result.object = itemResult.object;
//        }
//
//        return result;
//    }
    @Override
    public String toString() {
        return areaName;
    }
}
